package nacos

import (
	"net"
	"strconv"
	"strings"

	log "github.com/sirupsen/logrus"

	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/model"
	"github.com/nacos-group/nacos-sdk-go/vo"
)

type client struct {
	ip string 
	port int 
	nacosServerAddr string 
	nacosServerPort int 
	nacosServiceName string 
	nacosServiceGroup string 
	namingClient naming_client.INamingClient
}

func newClient(nacosServer string, nacosServiceName string, nacosServiceGroup string) *client {
	arr := strings.Split(nacosServer, ",")

	c := new(client)
	c.nacosServerAddr = arr[0]
	c.nacosServerPort, _ = strconv.Atoi(arr[1])

	c.nacosServiceName = nacosServiceName
	c.nacosServiceGroup = nacosServiceGroup
	c.ip = getIp()
	c.port = 8080

	clientConfig := constant.ClientConfig {
		NamespaceId: "",
		TimeoutMs: 5000,
		NotLoadCacheAtStart: true,
		LogDir: "/tmp/nacos/log",
		CacheDir: "/tmp/nacos/cache",
		LogLevel: "debug",
	}

	serverConfigs := []constant.ServerConfig {
		{
			IpAddr: c.ip,
			Port: uint64(c.nacosServerPort),
			ContextPath: "/nacos",
			Scheme: "http",
		},
	}

	param := vo.NacosClientParam {
		ClientConfig: &clientConfig,
		ServerConfigs: serverConfigs,
	}
	cli, err := clients.NewNamingClient(param)
	if err != nil {
		log.Fatal("init nacos failed")
	}

	c.namingClient = cli 
	return c
}

func (c *client) register(up bool) {
	param := c.newRegisterParam(up)
	c.namingClient.RegisterInstance(param)
}

func (c *client) deRegister() {

	param := vo.DeregisterInstanceParam {
		Ip: c.ip,
		Port: uint64(c.port),
		ServiceName: c.nacosServiceName,
		Ephemeral: true,
	}
	c.namingClient.DeregisterInstance(param)
}

func (c *client) getAllService() (map[string]model.Service, error) {
	param := vo.GetAllServiceInfoParam{
		PageNo: 1,
		PageSize: 500,
	}

	serviceMap := map[string]model.Service{}
	serviceList, err := c.namingClient.GetAllServicesInfo(param)
	if err != nil {
		return serviceMap, err
	}

	for _, serviceName := range serviceList.Doms {
		serviceParam := vo.GetServiceParam{
			ServiceName: serviceName,
		}
		service, err := c.namingClient.GetService(serviceParam)
		if err == nil {
			serviceMap[serviceName] = service
		}
	}
	return serviceMap, nil
}

func (c *client) newRegisterParam(up bool) vo.RegisterInstanceParam {

	param := vo.RegisterInstanceParam {
		Ip: c.ip,
		Port: uint64(c.port),
		Weight: 100,
		Enable: up,
		Healthy: up,
		Metadata: map[string]string{},
		Ephemeral: true,
	}
	if c.nacosServiceGroup != "" {
		param.Metadata["group"] = c.nacosServiceGroup
	}
	return param
}

func getIp() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		log.Fatal(err)
	}

	for _, addr := range addrs {
		ipnet, ok := addr.(*net.IPNet)
		if ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
			return ipnet.IP.String()
		}
	}

	return ""
}